﻿namespace JoinBox.Basal;

using System;
using System.Collections.Generic;
using System.IO;

public static partial class FileHelper
{
    /// <summary>
    /// 判断是文件还是目录(目录包括磁盘)
    /// </summary>
    /// <param name="filePath">路径</param>
    /// <returns>返回true为一个文件夹,返回false为一个文件</returns>
    public static bool IsDir(string filePath)
    {
        return !IsFile(filePath);
    }

    /// <summary>
    /// 判断是文件还是目录(目录包括磁盘)
    /// </summary>
    /// <param name="filePath">路径</param>
    /// <returns>返回true为一个文件,返回false为一个目录</returns>
    public static bool IsFile(string filePath)
    {
        var fi = new FileInfo(filePath);
        return (fi.Attributes & FileAttributes.Directory) == 0;
    }

    /// <summary>
    /// 将文件转换成byte[] 数组  File.ReadAllBytes
    /// </summary>
    /// <param name="fileUrl">文件路径文件名称</param>
    /// <returns>byte[]</returns>
    public static byte[]? GetFileData(string fileUrl)
    {
        using var fs = new FileStream(fileUrl, FileMode.Open, FileAccess.Read);
        byte[] buffur = new byte[fs.Length];
        fs.Read(buffur, 0, (int)fs.Length);
        return buffur;
    }

    /// <summary>
    /// 将文件转换成byte[] 数组
    /// </summary>
    /// <param name="fileUrl">文件路径文件名称</param>
    /// <returns>byte[]</returns>
    public static byte[] AuthGetFileData(string fileUrl)
    {
        using var fs = new FileStream(fileUrl, FileMode.OpenOrCreate, FileAccess.ReadWrite);
        byte[] buffur = new byte[fs.Length];
        using (var bw = new BinaryWriter(fs))
        {
            bw.Write(buffur);
            bw.Close();
        }
        return buffur;
    }

    /// <summary>
    /// 遍历目录
    /// </summary>
    /// <param name="dir"></param>
    /// <param name="list"></param>
    public static void Director(string dir, List<string> list)
    {
        var d = new DirectoryInfo(dir);
        var files = d.GetFiles(); // 文件
        foreach (var f in files)
            list.Add(f.Name);// 添加文件名到列表中

        var directs = d.GetDirectories(); // 文件夹
        // 获取子文件夹内的文件列表,递归遍历
        foreach (var dd in directs)
            Director(dd.FullName, list);
    }
}


public static partial class FileHelper
{
    /// <summary>
    /// 每次拷贝的文件大小被除数
    /// </summary>
    public const int CopyFileSize = 1024 * 1024 * 4;
    /// <summary>
    /// 计算一个文件的进度条大小
    /// </summary>
    /// <param name="fs">文件流</param>
    /// <returns></returns>
    public static int Jisuan(FileStream fs)
    {
        // 根据一次传输的大小,计算最大传输个数.
        // Math.Ceiling 方法 (Double),返回大于或等于指定的双精度浮点数的最小整数值
        return Convert.ToInt32(Math.Ceiling(fs.Length / (double)CopyFileSize));
    }

    /// <summary>
    /// 获取来源所有文件大小
    /// </summary>
    /// <param name="spath">来源路径</param>
    /// <param name="daxiao">返回所有文件的大小</param>
    public static void GetAllFileLength(string spath, ref int daxiao)// int可能会爆
    {
        DirectoryInfo dir = new(spath);
        // 获取本文件夹所有文件
        var fil = dir.GetFiles();
        foreach (FileInfo f in fil)
        {
            try
            {
                var formerOpenStream = new FileStream(f.FullName, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite);
                daxiao += Jisuan(formerOpenStream);
                formerOpenStream.Flush();
                formerOpenStream.Close();
                formerOpenStream.Dispose();
            }
            catch (Exception ex)
            {
                throw new Exception("GetAllFileLength A01\n" + ex.Message);
            }
        }
        // 获取子文件夹内的文件列表,递归遍历
        var dii = dir.GetDirectories();
        foreach (DirectoryInfo d in dii)
        {
            GetAllFileLength(d.FullName, ref daxiao);
        }
    }
}
public static partial class FileHelper
{
    /// <summary>
    /// 删除空白文件夹
    /// </summary>
    /// <param name="path">路径</param>
    /// <returns>成功true,失败false</returns>
    public static bool DelFolder(string path)
    {
        bool flag = false;
        try
        {
            if (Directory.Exists(path))
            {
                var aa = new DirectoryInfo(path)
                {
                    Attributes = FileAttributes.Normal// 设置文件夹属性为普通
                };
                aa.Delete();
                flag = true;
            }
        }
        catch
        { }
        return flag;
    }
    /// <summary>
    /// 新建文件夹
    /// </summary>
    /// <param name="path">路径</param>
    /// <returns>成功true,失败false</returns>
    public static bool NewFolder(string path)
    {
        bool flag = false;
        if (!Directory.Exists(path))
        {
            Directory.CreateDirectory(path)
                     .Attributes = FileAttributes.Normal; // 设置文件夹属性为普通
            flag = true;
        }
        return flag;
    }
    /// <summary>
    /// 重命名文件名字,如果路径还存在就名字+1
    /// </summary>
    /// <param name="path">文件路径</param>
    /// <returns>返回最终的名字,文件不在返回""</returns>
    public static string RenameFile(string path)
    {
        string str = path;
        if (File.Exists(str))
        {
            int a = 1;
            try
            {
                var dir = new FileInfo(str)
                {
                    Attributes = FileAttributes.Normal // 设置为普通文件
                };
                string qianzhList = dir.DirectoryName + "\\"; // "D:\\K01.惊惊连盒\\03.用户配置"
                while (true)
                {
                    string name = Path.GetFileNameWithoutExtension(path);
                    string pathFull = qianzhList + name + a.ToString() + dir.Extension;
                    if (!File.Exists(pathFull))// 如果没有这个文件
                    {
                        dir.MoveTo(pathFull);// 就重命名这个文件名
                        str = pathFull;
                        break;
                    }
                    else
                    {
                        a++;
                    }
                }
            }
            catch
            {
                throw new Exception("RenameFile重命名文件名出错");
            }
        }
        return str;
    }
    /// <summary>
    /// 路径中包含某个文件夹,有就返回文件夹路径
    /// </summary>
    /// <param name="dwgPath">路径</param>
    /// <param name="name">文件夹名称</param>
    /// <returns>成功返回含有这个文件夹名称的路径,失败返回""</returns>
    public static string GetPathIncludeString(string dwgPath, string name)
    {
        // 遍历路径中第几级有"01.饰施图"
        char ca = '\\';
        var dwgPaths = dwgPath.Split(ca);
        var st = new List<string>();
        for (int i = 0; i < dwgPaths.Length; i++)
        {
            if (dwgPaths[i] == name)
                break;
            else
                st.Add(dwgPaths[i]);// 把前面的路径合并起来
        }
        // 如果两个数组相同,表示路径没有"01.饰施图"
        string x = "";
        if (st.Count != dwgPaths.Length)
        {
            foreach (string item in st)
                x += item + "\\";
            x += name;
        }
        return x;
    }
    /// <summary>
    /// 列出路径文件,过滤为目标后缀
    /// </summary>
    /// <param name="path">路径</param>
    /// <param name="searchPattern">获取后缀的文件</param>
    /// <returns></returns>
    public static List<string> GetThisFolderFiles(string path,
          string searchPattern = "*.txt",
          SearchOption se = SearchOption.TopDirectoryOnly)
    {
        List<string> list = new();
        var theFolder = new DirectoryInfo(path);
        if (!theFolder.Exists)
            return list;
        // 仅本目录
        var thefileInfo = theFolder.GetFiles(searchPattern, se);
        foreach (FileInfo NextFile in thefileInfo) // 遍历文件
            list.Add(NextFile.FullName);
        return list;
    }
    /// <summary>
    /// 获取路径下所有文件以及子文件夹中文件
    /// </summary>
    /// <param name="path">全路径根目录</param>
    /// <param name="extension">后缀名.dwg</param>
    /// <returns></returns>
    public static List<string> GetFiles(string? path, string? extension = null)
    {
        var pas = new List<string>();
        GetFiles(path, extension, pas);
        return pas;
    }
    /// <summary>
    /// 获取路径下所有文件以及子文件夹中文件
    /// </summary>
    /// <param name="path">全路径根目录</param>
    /// <param name="extension">后缀名.dwg</param>
    /// <param name="pas">传入集合</param>
    /// <returns></returns>
    static void GetFiles(string? path, string? extension, List<string> pas)
    {
        if (path is null || string.IsNullOrEmpty(path))
            throw new ArgumentNullException(nameof(path));

        var dirInfo = new DirectoryInfo(path);
        // 获取本文件夹所有文件
        var fil = dirInfo.GetFiles();
        foreach (var f in fil)
        {
            if (extension is null)
            {
                if (string.IsNullOrEmpty(extension))
                    pas.Add(f.FullName);// 保存文件路径到表中
            }
            else
            {
                if (f.Extension.ToUpper() == extension.ToUpper())
                    pas.Add(f.FullName);// 保存文件路径到表中
            }
        }
        // 获取子文件夹内的文件列表,递归遍历
        var dir = dirInfo.GetDirectories();
        foreach (var d in dir)
            GetFiles(d.FullName, extension, pas);
    }
    /// <summary>
    /// 判断文件是否被程序占用
    /// </summary>
    /// <param name="fileName">文件路径</param>
    /// <returns>true表示正在使用,false没有使用</returns>
    public static bool IsFileInUse(string fileName)
    {
        bool inUse = true;
        if (!File.Exists(fileName))
            return false;

        FileStream? file = null;
        try
        {
            file = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.None);
            inUse = false;
        }
        finally
        {
            file?.Close();
        }
        return inUse;
    }
}

public static partial class FileHelper
{
    /// <summary>
    /// 删除母目录下所有文件
    /// </summary>
    /// <param name="pathDel">路径</param>
    /// <param name="progressBarAction">进度条回调</param>
    public static void DelPath(string pathDel, Action<int>? progressBarAction = null)
    {
        pathDel = pathDel.Trim('\\');
        string pathUp = StringHelper.PathHigherLevel(pathDel);
        // 删除所有子文件和子目录
        DelDirectory(pathDel, progressBarAction);

        // 子目录和文件数都是0,才能删除母文件夹
        if (Directory.GetDirectories(pathUp).Length == 0 &&
            Directory.GetFiles(pathUp).Length == 0)
            DelDirectory(new DirectoryInfo(pathUp), progressBarAction);// 删除目录
    }

    /// <summary>
    /// 递归子目录
    /// </summary>
    /// <param name="pathDel">来源</param>
    /// <param name="progressBarAction">进度条回调</param>
    static void DelDirectory(string pathDel, Action<int>? progressBarAction = null)
    {
        var dir = new DirectoryInfo(pathDel);// 目录
        var dirs = dir.GetDirectories();     // 子目录
        if (dirs.Length > 0)
        {
            // 先处理子目录的文件
            for (int i = 0; i < dirs.Length; i++)
            {
                var dirInfo = dirs[i];
                // 子目录如果是文件夹,就嵌套进去
                var attr = File.GetAttributes(dirInfo.FullName);
                if (attr == FileAttributes.Directory)
                    DelDirectory(dirInfo.FullName, progressBarAction);// 递归进去删除目录
                else
                    DelDirectory(dirInfo, progressBarAction);// 删除目录
            }
        }
        DelDirectory(dir, progressBarAction);// 删除目录
    }
    /// <summary>
    /// 删除目录和文件
    /// </summary>
    /// <param name="dirInfo">目录</param>
    /// <param name="progressBarAction">进度条回调</param>
    static void DelDirectory(DirectoryInfo dirInfo, Action<int>? progressBarAction = null)
    {
        var files = dirInfo.GetFiles(); // 获取所有文件
        for (int i = 0; i < files.Length; i++)
            DelFile(files[i], progressBarAction); // 删除文件并修改进度条

        dirInfo.Attributes = FileAttributes.Normal; // 设置为普通目录
        dirInfo.Delete(true);
    }
    /// <summary>
    /// 删除单个文件,修改进度条
    /// </summary>
    /// <param name="file">文件</param>
    /// <param name="progressBarAction">进度条回调</param>
    public static void DelFile(string file, Action<int>? progressBarAction = null)
    {
        var fileInfo = new FileInfo(file);
        DelFile(fileInfo, progressBarAction);
    }
    /// <summary>
    /// 删除文件,修改进度条
    /// </summary>
    /// <param name="file">文件</param>
    /// <param name="progressBarAction">进度条回调</param>
    static void DelFile(FileInfo file, Action<int>? progressBarAction = null)
    {
        if (!file.Exists)
            return;

        // 设置为普通文件
        file.Attributes = FileAttributes.Normal;
        // 计算进度条
        var fs = new FileStream(file.FullName,
            FileMode.Open, FileAccess.Read, FileShare.ReadWrite);

        progressBarAction?.Invoke(Jisuan(fs));
        // int a = progressBar1.Value - Jisuan(fs, CopyFileSize);/*当前值减去-*/
        // if (progressBar1.Minimum < a)
        //    progressBar1.Value = a;
        // else
        //    progressBar1.Value = progressBar1.Minimum;

        fs.Close();
        fs.Dispose();
        file.Delete();
    }
}


public static partial class FileHelper
{
    /// <summary>
    /// 复制文件到文件,文件到路径,路径到路径
    /// </summary>
    /// <param name="sPath"></param>
    /// <param name="dPath"></param>
    /// <param name="progressBarAction">进度条回调</param>
    public static void Copy(string sPath, string dPath, Action<int>? progressBarAction = null)
    {
        if (sPath.Length - 1 > 0 && sPath.Length - 1 > 0)
        {
            sPath = sPath.Trim();
            while (sPath[sPath.Length - 1] == '\\')
                sPath = sPath.Substring(0, sPath.Length - 1);

            dPath = dPath.Trim();
            while (dPath[dPath.Length - 1] == '\\')
                dPath = dPath.Substring(0, dPath.Length - 1);

            if (File.Exists(sPath)) // 来源是文件,复制到路径
                CopyOneFileToDirectory(sPath, dPath, progressBarAction);
            else if (Directory.Exists(sPath)) // 来源是路径,复制到路径
                CopyDirectoryToDirectory(sPath, dPath, progressBarAction);
        }
    }
    /// <summary>
    /// 递归拷贝所有子路径
    /// </summary>
    /// <param name="sPath">来源</param>
    /// <param name="dPath">目标</param>
    /// <param name="progressBarAction">进度条回调</param>
    static void CopyDirectoryToDirectory(string sPath, string dPath, Action<int>? progressBarAction = null)
    {
        NewFolder(dPath);
        var dir = new DirectoryInfo(sPath);// 当前路径
        CopyAllFileToDirectory(dir, dPath, progressBarAction);
        var dirs = dir.GetDirectories();

        // 获取所有子路径
        for (int i = 0; i < dirs.Length; i++)
        {
            var sourceDirectories = dirs[i];
            var sFull = sourceDirectories.FullName;// 来源完整路径
            var tFull = sFull.Replace(sPath, dPath);// 目标完整路径
            NewFolder(tFull);
            CopyAllFileToDirectory(sourceDirectories, tFull, progressBarAction);
            CopyDirectoryToDirectory(sFull, tFull, progressBarAction);
        }
    }
    /// <summary>
    /// 复制路径下所有文件到目标路径
    /// </summary>
    /// <param name="sPath">来源路径</param>
    /// <param name="dPath">目标路径</param>
    static void CopyAllFileToDirectory(DirectoryInfo sPath, string dPath, Action<int>? progressBarAction = null)
    {
        var files = sPath.GetFiles();// 获取所有文件
        if (files.Length > 0)
        {
            foreach (var file in files)// 遍历所有文件
            {
                file.Attributes = FileAttributes.Normal;            // 设置为普通文件
                string sFile = file.FullName;                       // 文件的全路径
                string dFile = sFile.Replace(sPath.FullName, dPath);// sFile完整路径 和 前缀路径 差异=文件名,接到dPath后面
                SFileToDFile(sFile, dFile, progressBarAction);
            }
        }
    }

    /// <summary>
    /// 复制路径下某个文件到路径
    /// </summary>
    /// <param name="sFile">文件,要完整路径</param>
    /// <param name="dPath">目标路径</param>
    /// <returns></returns>
    static void CopyOneFileToDirectory(string sFile, string dPath, Action<int>? progressBarAction = null)
    {
        NewFolder(dPath);
        string dFile = Path.Combine(dPath, Path.GetFileName(sFile));
        SFileToDFile(sFile, dFile, progressBarAction);
    }
    /// <summary>
    /// 复制文件到文件
    /// </summary>
    /// <param name="sFile"></param>
    /// <param name="dFile"></param>
    public static void SFileToDFile(string sFile, string dFile, Action<int>? progressBarAction = null)
    {
        // 多线程占用文件
        // https://www.cnblogs.com/Tench/p/CSharpSimpleFileWriteLock.html
        // https://www.cnblogs.com/kongyiyun/archive/2011/11/15/2249108.html

        try
        {
            // 创建目的文件,如果已存在将被覆盖
            var fileToCreate = new FileStream(dFile, FileMode.Create, FileAccess.ReadWrite, FileShare.ReadWrite);
            fileToCreate.Close();   // 关闭所有fileToCreate的资源
            fileToCreate.Dispose(); // 释放所有fileToCreate的资源
        }
        catch (Exception ex)
        {
            throw new ArgumentException("SFileToDFile 2\n" + ex.Message);
        }

        FileStream? sFileStream = null; // 源文件
        FileStream? dFileStream = null; // 目标
        try
        {
            sFileStream = new FileStream(sFile,
                     FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite);// ReadWrite 共享也可以打开
            dFileStream = new FileStream(dFile,
                     FileMode.Append, FileAccess.Write, FileShare.ReadWrite);// 以写方式打开目标文件

            int FileSize;// 每次要拷贝的文件的大小
            if (CopyFileSize < sFileStream.Length)// 如果分段拷贝,即每次拷贝内容小于文件总长度
            {
                byte[] buffer = new byte[CopyFileSize]; // 根据传输的大小,定义一个字节数组,用来存储传输的字节
                int copied = 0;                     // 记录传输的大小
                int tem_n = 1;                      // 设置进度栏中进度的增加个数
                while (copied <= ((int)sFileStream.Length - CopyFileSize))
                {
                    FileSize = sFileStream.Read(buffer, 0, CopyFileSize); // 从0开始读到buffer字节数组中,每次最大读TranSize
                    sFileStream.Flush();                              // 清空缓存
                    dFileStream.Write(buffer, 0, CopyFileSize);           // 向目的文件写入字节
                    dFileStream.Flush();                              // 清空缓存
                    dFileStream.Position = sFileStream.Position; // 是源文件的目的文件流的位置相同
                    copied += FileSize;                                    // 记录已经拷贝的大小

                    progressBarAction?.Invoke(tem_n);
                    // if (progressBar1 is not null)
                    // {
                    //    int a = progressBar1.Value + tem_n;// 增加进度栏的进度块
                    //    if (progressBar1.Maximum > a)
                    //        progressBar1.Value = a;
                    //    else
                    //        progressBar1.Value = progressBar1.Maximum;
                    // }
                }
                int leftSize = (int)sFileStream.Length - copied;  // 获取剩余文件的大小
                FileSize = sFileStream.Read(buffer, 0, leftSize); // 读取剩余的字节
                sFileStream.Flush();
                dFileStream.Write(buffer, 0, leftSize); // 写入剩余的部分
                dFileStream.Flush();
            }
            else // 如果整体拷贝,即每次拷贝内容大于文件总长度
            {
                byte[] buffer = new byte[sFileStream.Length];
                sFileStream.Read(buffer, 0, (int)sFileStream.Length);
                sFileStream.Flush();
                dFileStream.Write(buffer, 0, (int)sFileStream.Length);
                dFileStream.Flush();

                progressBarAction?.Invoke(Jisuan(sFileStream));
                // if (progressBar1 is not null)
                // {
                //    int a = progressBar1.Value + Jisuan(formerOpenStream);// 增加进度栏的进度块
                //    if (progressBar1.Maximum > a)
                //        progressBar1.Value = a;
                //    else
                //        progressBar1.Value = progressBar1.Maximum;
                // }
            }
        }
        catch (Exception ex)
        {
            throw new ArgumentException("SFileToDFile 3\n" + ex.Message);
        }
        finally
        {
            sFileStream?.Close();
            sFileStream?.Dispose();
            dFileStream?.Close();
            dFileStream?.Dispose();
        }
    }
}
